/*
 ============================================================================
 Name        : tangoc.c
 Author      : Jessay
 Version     :
 Copyright   : Your copyright notice
 Description : Hello World in C, Ansi-style
 ============================================================================
 */

#include <time.h>
#include <sys/time.h>
#include <sys/select.h>
#include "tangoc.h"

#define BUF_SIZE 			296
#define RAW_CTRL_CONFIG 	0x88
#define RAW_ADDR 			0x8E
#define engineer_mode_reg 	61
#define cross_y_register 	139
#define eeprom_read_addr 	59
#define slave_version 		64
#define specop 				58
#define INT_MODE 			52
#define INT_width 			53

#define TUNE_MODE_CONFIG    96
#define TUNE_CTRL 			138

// define the RAW control register
static unsigned int RAW_CTRL_register;
// RAW_CTRL bits definition
#define ONE_UINT16			((unsigned int) 1)
#define CHOOSE_0 			(ONE_UINT16 << 0)	// Choose function (bit0)
#define CHOOSE_1 			(ONE_UINT16 << 1)	// Choose function (bit1) (0: history buffer, 1: RAW data, 2: system info)
#define METHOD 				(ONE_UINT16 << 2)	// Method 0 or 1
#define OFFSET_LOWPASS 		(ONE_UINT16 << 3)	// Enables the offset correction and the low-pass filter
#define SENSITIVITY			(ONE_UINT16 << 4)	// Show ME0 sensitivity adjustment (OFFSET must also be set)
#define M1_PATTERN 			(ONE_UINT16 << 5)	// ME1 pattern (0:pat4, 1:pat8)
#define M1_ROTATION 		(ONE_UINT16 << 6)	// ME1 sense direction (0:Y, 1:X)
#define M1_BAND 			(ONE_UINT16 << 7)	// ME1 band scan (0:single cross node, 1:full X axis scan reported in RAW table)
#define NO_ALGO				(ONE_UINT16 << 8)	// Enables single shot RAW refresh
#define SINGLE_SHOT 		(ONE_UINT16 << 9)	// Disables the algo
#define FREEZE				(ONE_UINT16 << 10)	// RAW refresh freezed after single shot is done	
#define DRIFT_COMP       	(ONE_UINT16 << 11)	// Enable drift comp (For raw data measures)"
#define RAWDATA_S00       	(ONE_UINT16 << 12)	// Raw data display selection 0
#define RAWDATA_S11       	(ONE_UINT16 << 13)	// Raw data display selection 1
#define RAWDATA_S22       	(ONE_UINT16 << 14)	// Raw data display selection 2
#define RAWDATA_S33       	(ONE_UINT16 << 15)	// Raw data display selection 3

// define the TUNE control register
static unsigned int TUNE_CTRL_register;
// TUNE_CTRL bits definition
#define RAWDATA_S0       		(ONE_UINT16 << 0)	// Raw data display selection 0
#define RAWDATA_S1       		(ONE_UINT16 << 1)	// Raw data display selection 1
#define RAWDATA_S2       		(ONE_UINT16 << 2)	// Raw data display selection 2
#define RAWDATA_S3       		(ONE_UINT16 << 3)	// Raw data display selection 3

// define the tune mode register
static unsigned int tune_mode_register=0;
// tune mode bits definition
#define ONE_UINT16	((unsigned int) 1)
#define TUNING  	(ONE_UINT16 << 0)	// Standard tuning is possible
#define QUALIFY 	(ONE_UINT16 << 1)	// Qualification mode with automatic scan
										// and output for the M1 noise qualification
#define DISPLAY		(ONE_UINT16 << 2)	// Variable data displays can be selected
#define ALGO		(ONE_UINT16 << 3)	// Start algorithm see two finger drawing

static int gcmd;

int attb_value()
{
	unsigned char buf[1];
	read(gdev, buf, 1);
	return buf[0];
}

unsigned int read_raw_ctrl_reg()
{
	unsigned char wbuf[1], rbuf[2];
	wbuf[0] = RAW_CTRL_CONFIG;
	write(gdev, wbuf, 1);
	read(gdev, rbuf, 2);
	return (unsigned int) (rbuf[0] || rbuf[1] << 8);
}

void raw_delay(int n)
{
	int i, cnt, maxt=20000;

	ioctl(gdev, ATTB_VALUE, 0);
	for (i = 0; i < n; i++)
	{
		cnt = 0;
		while (1) // high
		{
			if (attb_value()) break;
			else
			{
				if (cnt++ > maxt) break;
			}
		}
		cnt = 0;
		while (1) // low
		{
			if (!attb_value()) break;
			else
			{
				if (cnt++ > maxt) break;
			}
		}
	}
	ioctl(gdev, DEFAULT, 0);
}

unsigned char read_INT()
{
	int i;
	unsigned char wbuf[1], rbuf[1];

	wbuf[0] = INT_MODE;
	for(i=0; i<3; i++)
	{
		write(gdev, wbuf, 1);
		read(gdev, rbuf, 1);
		if (rbuf[0]) break;
		msleep(100);
	}
	if(rbuf[0]==0)
	{
		puts("Read_INT failed.");
	}
	return rbuf[0];
}

int write_INT(unsigned char dat)
{
	unsigned char wbuf[2];

	wbuf[0] = INT_MODE;
	wbuf[1] = dat & 0xFF;
	return write(gdev, wbuf, 2)==2? 1: 0;
}

void write_raw_ctrl_reg(void)
{
	unsigned char mode;
	unsigned char wbuf[8];

	mode = read_INT();
	write_INT(0x08);
	wbuf[0] = RAW_CTRL_CONFIG;
	wbuf[1] = RAW_CTRL_register & 0xFF;
	wbuf[2] = (RAW_CTRL_register >> 8) & 0xFF;
	write(gdev, wbuf, 3);

	raw_delay(2);
	write_INT(mode);
}

void write_tune_ctrl_reg (void)
{
	unsigned char wbuf[8];
	wbuf[0] = TUNE_CTRL;
	wbuf[1] = TUNE_CTRL_register & 0xFF;
	write(gdev, wbuf, 2);
}

void write_tune_mode_reg()
{
	 unsigned char wbuf[8];
	 wbuf[0] = TUNE_MODE_CONFIG;
	 wbuf[1] = tune_mode_register & 0xFF;
	 write(gdev, wbuf, 2);
}


void enable_algo(void)
{
	RAW_CTRL_register &= ~NO_ALGO;
	write_raw_ctrl_reg();
}

void disable_algo(void)
{
	RAW_CTRL_register |= NO_ALGO;
	write_raw_ctrl_reg();
}

void getXYN(unsigned char buf[], int len)
{
	unsigned int RAW_CTRL_register_save = RAW_CTRL_register;
	unsigned char wbuf[8];

	RAW_CTRL_register = CHOOSE_1;
	write_raw_ctrl_reg();

	ioctl(gdev, DEFAULT, 0);
	wbuf[0] = RAW_ADDR;
	write(gdev, wbuf, 1);
	msleep(50);
	read(gdev, buf, 2);

	//recover RAW_CTRL_register
	RAW_CTRL_register = RAW_CTRL_register_save;
	write_raw_ctrl_reg();
}

int read_raw(unsigned char buf[], int len, int addr)
{
	int ret = 0;
	unsigned char wbuf[8];

	wbuf[0] = addr;//RAW_ADDR; //0x8E
//	if(gcmd==DEBUG_EEPROM_OFFSET || gcmd==DEBUG_ORIGIN_MODE ||
//			gcmd==DEBUG_RAM_OFFSET || gcmd==TUNE_DEBUG)
	{
		ret = write(gdev, wbuf, 1);
		if (ret == 1)
		{
			ret = read(gdev, buf, len);
		}
	}
//	else
//	{
//		unsigned char i, j;
//		unsigned char rbuf[256];
//		unsigned char N = XN * 2;
//		for (j = 0; j < YN; j++)
//		{
//			char tmp[4];
//			tmp[0] = cross_y_register;
//			tmp[1] = j;
//			ret = write(gdev, tmp, 2);
//
//			raw_delay(1);
//
//			ret = write(gdev, wbuf, 1);
//			read(gdev, rbuf, N);
//			for (i = 0; i < N; i++)
//			{
//				buf[j * N + i] = rbuf[i];
//			}
//		}
//	}
	return ret;
}

int read_raster(unsigned char buf[], int XN, int YN)
{
	int ret = 0;
	unsigned char wbuf[8];

	wbuf[0] = RAW_ADDR; //0x8E
	unsigned char i, j;
	unsigned char rbuf[256];
	unsigned char N = XN * 2;
	for (j = 0; j < YN; j++)
	{
		char tmp[4];
		tmp[0] = cross_y_register;
		tmp[1] = j;
		ret = write(gdev, tmp, 2);

		raw_delay(1);

		ret = write(gdev, wbuf, 1);
		read(gdev, rbuf, N);
		for (i = 0; i < N; i++)
		{
			buf[j * N + i] = rbuf[i];
		}
	}
	return ret;
}

void set_mode(int cmd, int arg)
{
	ioctl(gdev, DEFAULT, 0);
	gcmd = cmd;
	switch (cmd)
	{
	case DEBUG_ORIGIN_MODE:
		RAW_CTRL_register = 0;
		RAW_CTRL_register |= CHOOSE_0;
		write_raw_ctrl_reg();
		disable_algo();
		break;

	case DEBUG_EEPROM_OFFSET:
		RAW_CTRL_register = 0;
		RAW_CTRL_register |= CHOOSE_0;
		RAW_CTRL_register |= OFFSET_LOWPASS;
		write_raw_ctrl_reg();
		disable_algo();
		break;

	case DEBUG_RAM_OFFSET:
		RAW_CTRL_register = 0;
		RAW_CTRL_register |= CHOOSE_0;
		RAW_CTRL_register |= RAWDATA_S11;
		write_raw_ctrl_reg();
		disable_algo();
		break;

	case TUNE_DEBUG:
		tune_mode_register = 0; //config tune mode register
		tune_mode_register |= TUNING;
		write_tune_mode_reg();
		RAW_CTRL_register = 0; //config rawctrl register
		RAW_CTRL_register |= CHOOSE_0;
		disable_algo();
		TUNE_CTRL_register = 0; //config tunectrl register
		write_tune_ctrl_reg();
		break;

	case RASTER_ORIGIN_MODE:
		RAW_CTRL_register = 0;
		RAW_CTRL_register |= CHOOSE_0;
		RAW_CTRL_register |= METHOD;
		RAW_CTRL_register |= M1_BAND;
		write_raw_ctrl_reg();
		disable_algo();
		break;

	case RASTER_EEPROM_OFFSET:
		RAW_CTRL_register = 0;
		RAW_CTRL_register |= CHOOSE_0;
		RAW_CTRL_register |= METHOD;
		RAW_CTRL_register |= M1_BAND;
		RAW_CTRL_register |= OFFSET_LOWPASS;
		write_raw_ctrl_reg();
		disable_algo();
		break;

	case RASTER_LX_SY:
		tune_mode_register = 0; //config tune mode register
		tune_mode_register |= TUNING;
		write_tune_mode_reg();
		RAW_CTRL_register = 0; //config rawctrl register
		RAW_CTRL_register |= CHOOSE_0;
		RAW_CTRL_register |= METHOD;
	//	RAW_CTRL_register |= OFFSET_LOWPASS;
		RAW_CTRL_register |= M1_BAND;
		RAW_CTRL_register |= RAWDATA_S00;
		RAW_CTRL_register |= RAWDATA_S22;
		disable_algo();
		TUNE_CTRL_register = 0; //config tunectrl register
		TUNE_CTRL_register |= RAWDATA_S0;
		TUNE_CTRL_register |= RAWDATA_S2;
		write_tune_ctrl_reg();
		RAW_CTRL_register |= M1_ROTATION;
		write_raw_ctrl_reg();
		break;

	case RASTER_LX_SY_OFFSET:
		tune_mode_register = 0; //config tune mode register
		tune_mode_register |= TUNING;
		write_tune_mode_reg();
		RAW_CTRL_register = 0; //config rawctrl register
		RAW_CTRL_register |= CHOOSE_0;
		RAW_CTRL_register |= METHOD;
		RAW_CTRL_register |= OFFSET_LOWPASS;
		RAW_CTRL_register |= M1_BAND;
		RAW_CTRL_register |= RAWDATA_S00;
		RAW_CTRL_register |= RAWDATA_S22;
		disable_algo();
		TUNE_CTRL_register = 0; //config tunectrl register
		TUNE_CTRL_register |= RAWDATA_S0;
		TUNE_CTRL_register |= RAWDATA_S2;
		write_tune_ctrl_reg();
		RAW_CTRL_register |= M1_ROTATION;
		write_raw_ctrl_reg();
		break;

	case RASTER_LY_SX:
		tune_mode_register = 0; //config tune mode register
		tune_mode_register |= TUNING;
		write_tune_mode_reg();
		RAW_CTRL_register = 0; //config rawctrl register
		RAW_CTRL_register |= CHOOSE_0;
		RAW_CTRL_register |= METHOD;
		RAW_CTRL_register |= M1_BAND;
		RAW_CTRL_register |= RAWDATA_S00;
		RAW_CTRL_register |= RAWDATA_S22;
		disable_algo();
		TUNE_CTRL_register = 0; //config tunectrl register
		TUNE_CTRL_register |= RAWDATA_S0;
		TUNE_CTRL_register |= RAWDATA_S2;
		write_tune_ctrl_reg();
		break;

	case RASTER_LY_SX_OFFSET:
		tune_mode_register = 0; //config tune mode register
		tune_mode_register |= TUNING;
		write_tune_mode_reg();
		RAW_CTRL_register = 0; //config rawctrl register
		RAW_CTRL_register |= CHOOSE_0;
		RAW_CTRL_register |= METHOD;
		RAW_CTRL_register |= OFFSET_LOWPASS;
		RAW_CTRL_register |= M1_BAND;
		RAW_CTRL_register |= RAWDATA_S00;
		RAW_CTRL_register |= RAWDATA_S22;
		disable_algo();
		TUNE_CTRL_register = 0; //config tunectrl register
		TUNE_CTRL_register |= RAWDATA_S0;
		TUNE_CTRL_register |= RAWDATA_S2;
		write_tune_ctrl_reg();
		break;
	}
}

